import _ from 'lodash';
import express from 'express';
import logger from '../../common/logger';
import asyncHandler from 'express-async-handler';
import { AgentDto, AgentPageQuery } from '../../domain/model/agent/dtos';
import { AgentStatus } from '../../domain/model/agent/type';
import { agentService } from '../../domain/model/agent/service';
import { IExtendedStorage } from '../../infra/objectStorage/type';
import { configurationService } from '../../domain/service/configService';
import { SimulationJobService } from '../../domain/model/simulation/service';
import { SimJobStatus } from '../../domain/model/simulation/type';
import { Agent } from '../../domain/model/agent/entities/agent';
interface RegistratioResponse {
  storage: IExtendedStorage
}

export function init(app: express.Application) {
  app.get('/api/agents', asyncHandler(async (req, res) => {
    const agentDtos = await agentService.findAll();
    res.json({ success: true, agents: agentDtos });
  }));

  app.post('/api/agents', asyncHandler(async (req, res) => {
    const pageQuery: AgentPageQuery = req.body;
    let products = await agentService.findForPage(pageQuery);
    res.json({
      success: true,
      data: products
    });
  }));

  app.get('/api/agents/:product/:status', asyncHandler(async (req, res) => {
    const { product, status } = req.params;
    const agentDtos = await agentService.findByProductAndStatus(product, status);

    if (_.isEmpty(agentDtos)) {
      res.json({ success: true, agents: [] });
      return;
    }
    // build agent simulation job status count
    const agentIds = agentDtos.map((agentDto) => { return agentDto.identity; });
    const statuses = [SimJobStatus.Created, SimJobStatus.AgentAssigned, SimJobStatus.AgentDispatched, SimJobStatus.Running];
    const agentSimJobStatusCounts = await new SimulationJobService().countAgentSimulationJobStatus(agentIds, statuses, product);
    agentDtos.forEach(agentDto => {
      // running count
      const runningJobs = agentSimJobStatusCounts
        .filter(agentJobStatus => agentJobStatus.identity === agentDto.identity && agentJobStatus.status === SimJobStatus.Running);
      agentDto.runningJob = runningJobs.length > 0 ? _.toNumber(runningJobs[0].count) : 0;
      // queuing count
      // queuing: [SimJobStatus.AgentAssigned, SimJobStatus.AgentDispatched, SimJobStatus.Created]
      let queuingCount = 0;
      agentSimJobStatusCounts
        .filter(agentJobStatus => agentJobStatus.identity === agentDto.identity && agentJobStatus.status !== SimJobStatus.Running)
        .forEach(agentSimJob => {
          queuingCount += _.toNumber(agentSimJob.count);
        });
      agentDto.queuingJob = queuingCount;
    });

    res.json({ success: true, agents: agentDtos });
  }));

  app.post('/api/agent/check', asyncHandler(async (req, res) => {
    const { identity, password } = req.body;
    const agent = await agentService.findByIdentity(identity);
    let checkResult: boolean = false;
    if (agent && (agent.role === 'public' || (agent.role === 'private' && agent.password === password))) {
      checkResult = true;
    }
    res.json({ success: true, data: checkResult });
  }));

  app.post('/api/agent/registration', asyncHandler(async (req, res) => {
    logger.info(`received agent registration request ${JSON.stringify(req.body)}`);

    const { identity, advertiseIp, desc, products, port, role, password } = req.body;

    const dto = {} as AgentDto;
    dto.identity = identity;
    dto.desc = desc || '';
    dto.products = products;
    dto.port = port || 0;
    dto.advertiseIp = advertiseIp;
    dto.status = AgentStatus.ONLINE;
    dto.role = role || 'public';
    dto.password = password || '';


    await agentService.saveOrUpdateByIdentity(dto);

    const response = {} as RegistratioResponse;
    response.storage = configurationService.config.storage;

    res.json({ success: true, response });
  }));

  app.post('/api/agent/osInfo/:identity', asyncHandler(async (req, res) => {
    const { cpu, drive, memory } = req.body;

    const agent = {} as Agent;
    agent.identity = req.params.identity;
    agent.cpu = cpu;
    agent.drive = drive;
    agent.memory = memory;

    await agentService.updateByIdentity(agent);

    res.json({ success: true });
  }));

  // app.get('/findById', asyncHandler(async(req, res) => {

  //   const agentService = agentService;
  //   const result = await agentService.findById(1);
  //   res.json({ success: true, agents: result });
  // }));

  // app.get('/getAll', asyncHandler(async(req, res) => {
  //   const agentService = agentService;
  //   const result = await agentService.findAll();
  //   res.json({ success: true, agents: result });
  // }));

  // app.get('/findByIdentity', asyncHandler(async(req, res) => {

  //   const agentSerivce = agentService;

  //   const result = await agentSerivce.findByIdentity('sad');
    
  //   res.json({ success: true, agents: result });
  // }));

  // app.get('/api/test', asyncHandler(async(req, res) => {
  //   const agentService = agentService;

  //   const agentDto = {} as AgentDto;
  //   agentDto.advertiseIp = 'localhost';
  //   agentDto.desc = '描述';
  //   agentDto.identity = `${num++}`;
  //   agentDto.port = 333;
  //   agentDto.products = ['avl', 'asben'];
  //   agentDto.status = AgentStatus.ONLINE;

  //   const result = await agentService.save(agentDto);
  //   res.json({ success: true, agents: result });
  // }));

  // app.get('/api/test1', asyncHandler(async(req, res) => {
  //   const agentService = agentService;

  //   const agentDto = {} as AgentDto;
  //   agentDto.id = 4;
  //   agentDto.advertiseIp = 'localhost';
  //   agentDto.desc = '描述1';
  //   agentDto.identity = '333';
  //   agentDto.port = 333;
  //   agentDto.products = ['avl', 'asben'];
  //   agentDto.status = AgentStatus.ONLINE;

  //   const result = await agentService.save(agentDto);
  //   res.json({ success: true, agents: result });
  // }));

  // app.get('/api/product', asyncHandler(async(req, res) => {
  //   const agentService = agentService;
  //   const dtos = await agentService.findByProduct('matlab1');
  //   res.json({ success: true, agents: dtos });
  // }));
}